package com.yeskery.nut.application;

import com.yeskery.nut.annotation.boot.NutBootApplication;
import com.yeskery.nut.annotation.test.NutBootTest;
import com.yeskery.nut.bean.*;
import com.yeskery.nut.bean.scheduling.ScheduledExecutor;
import com.yeskery.nut.core.Path;
import com.yeskery.nut.core.*;
import com.yeskery.nut.event.*;
import com.yeskery.nut.http.BasicServerContext;
import com.yeskery.nut.plugin.*;
import com.yeskery.nut.scan.AnnotationScanHandler;
import com.yeskery.nut.script.AbstractScriptContext;
import com.yeskery.nut.script.ControllerPath;
import com.yeskery.nut.script.ControllerScript;
import com.yeskery.nut.script.FileScriptContext;
import com.yeskery.nut.script.function.Function;
import com.yeskery.nut.script.function.InternalFunctionRegister;
import com.yeskery.nut.script.parser.ExpressionScriptMetadataParser;
import com.yeskery.nut.test.TestAnnotationApplicationContext;
import com.yeskery.nut.transaction.TransactionRegistry;
import com.yeskery.nut.util.ClassLoaderUtils;
import com.yeskery.nut.util.IPUtils;
import com.yeskery.nut.util.banner.NutBanner;
import com.yeskery.nut.util.logging.NutLoggingInitializer;
import com.yeskery.nut.view.DefaultPostfixViewHandler;
import com.yeskery.nut.view.PostfixViewHandler;
import com.yeskery.nut.view.WebViewConfigureImpl;
import com.yeskery.nut.websocket.WebSocketConfiguration;
import com.yeskery.nut.websocket.WebSocketRegisterFactory;
import com.yeskery.nut.websocket.WebSocketServer;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * Nut应用对象
 * @author sprout
 * @version 1.0
 * 2023-04-22 18:03
 */
public final class NutApplication {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(NutApplication.class.getName());

    /** 默认启动 HTTP 的端口号 */
    private static final int HTTP_PORT = 8080;

    /** 默认启动 HTTPS 的端口号 */
    private static final int HTTPS_PORT = 8443;

    /** 服务状态 */
    private volatile int status = -1;

    /** 应用阻塞器 */
    private final ApplicationBlocker applicationBlocker = new ApplicationBlocker();

    /** Nut Banner对象 */
    private final NutBanner nutBanner = NutBanner.getInstance();

    /** 自动探测处理器 */
    private final AutoDetectorHandler autoDetectorHandler;

    /** Nut 配置接口 */
    private final NutConfigureImpl nutConfigureImpl = new NutConfigureImpl();

    /** 后缀视图处理器 */
    private final PostfixViewHandler postfixViewHandler = new DefaultPostfixViewHandler();

    /** NutServer构造工厂 */
    private final NutServerFactory nutServerFactory = new DefaultNutServerFactory();

    /** 服务元数据信息 */
    private final DefaultApplicationMetadata applicationMetadata = new DefaultApplicationMetadata();

    /** 服务事件上下文 */
    private final ServerEventContext serverEventContext = new ServerEventContext();

    /** 应用事件广播器 */
    private final ApplicationEventMulticaster applicationEventMulticaster;

    /** 线程池 */
    private final ThreadPool threadPool;

    /** 程序运行类型 */
    private ApplicationType applicationType;

    /** Nut基础配置对象 */
    private BasicNutConfigure basicNutConfigure;

    /** 应用上下文 */
    private ApplicationContext applicationContext;

    /** Web应用上下文 */
    private ApplicationContext webApplicationContext;

    /** Nut Server 服务器 */
    private NutServer nutServer;

    /** 脚本文件监听服务 */
    private WatchService watchService;

    {
        nutConfigureImpl.setControllerManager(NutControllerManager.getInstance());
        nutConfigureImpl.setPluginManager(new DefaultPluginManager());
        nutConfigureImpl.setWebViewConfigure(new WebViewConfigureImpl(postfixViewHandler));
        autoDetectorHandler = new DefaultAutoDetectorHandler(this);
        threadPool = new DefaultThreadPool();
        applicationEventMulticaster = new DefaultApplicationEventMulticaster(threadPool.getThreadPool());
        // 通过SPI加载预置事件监听器
        doLoadSpiApplicationEventListener();
    }

    /**
     * Nut 启动的主方法
     * @param nutConfiguration 配置对象
     * @param args 启动参数
     * @return 应用上下文
     */
    public ApplicationContext run(NutConfiguration nutConfiguration, String[] args) {
        if (status == ServerStatus.STARTING.getStatus() || status == ServerStatus.STARTED.getStatus()) {
            throw new NutException("Nut Server Starting Or Started.");
        }
        Thread nutServerRunThread = null;
        try {
            long startTime = System.currentTimeMillis();
            status = ServerStatus.STARTING.getStatus();

            // 配置参数合并
            MergeNutConfigure mergeNutConfigure = new MergeNutConfigure()
                    .merge(new EnvironmentConfigureAdapter())
                    .merge(new NutConfigurationConfigureAdapter(nutConfiguration))
                    .merge(new SystemEnvNutConfigure())
                    .merge(new JvmPropertiesNutConfigure())
                    .merge(new ArgsNutConfigure(args))
                    .apply(new NutConfigurationMergeConfigureFunction(nutConfiguration));
            mergeNutConfigure.initialize();

            this.basicNutConfigure = mergeNutConfigure;

            // 打印启动banner
            nutBanner.printBanner(mergeNutConfigure);

            // 初始化日志配置
            NutLoggingInitializer.init(mergeNutConfigure);

            // 发布服务启动事件
            applicationEventMulticaster.multicastEvent(new ApplicationStartingEvent(this));

            // 设置环境变量
            doInitEnvironment(mergeNutConfigure.getEnv(), args);

            // 通过系统环境变量、JVM参数以及启动参数来覆盖环境中参数值
            new ExternalEnvironmentParameterUpdater(getNutConfigure().getEnvironment(), args).updateEnvironmentParameter();

            // 根据环境配置参数重新进行日志配置初始化
            NutLoggingInitializer.init(mergeNutConfigure, getNutConfigure().getEnvironment());
            NutLoggingInitializer.resetLogConfigContent();

            // 初始化启动主类
            if (nutConfiguration.getMainClass() != null) {
                doInitMainClassSource(nutConfiguration.getMainClass(), nutConfiguration);
            }

            applicationType = nutConfiguration.getApplicationType();
            applicationMetadata.setApplicationType(applicationType);

            boolean isTestApplicationType = ApplicationType.isTestApplicationType(applicationType);
            applicationContext = isTestApplicationType
                    ? new TestAnnotationApplicationContext(this)
                    : new AnnotationApplicationContext(this);
            webApplicationContext = new WebApplicationContext(this);
            ((BaseApplicationContext) webApplicationContext).setBeanAnnotationScanMetadata(new ArrayList<>(16));

            // 注册默认应用上下文组件
            registerDefaultApplicationComponent();

            // 发布应用上下文启动事件
            applicationEventMulticaster.multicastEvent(new ApplicationContextStartingEvent(applicationContext));

            // 自动检测组件
            doInitAutoDetect();

            BindContext bindContext = new ApplicationBindContext(this);
            ((FactoryBeanRegister) applicationContext).registerBean("bindContext", bindContext, BindContext.class);
            BasePluginInitializer pluginInitializer = new ApplicationContextPluginInitializer(applicationContext);

            // 执行通过函数式编程方式设置的插件的绑定方法
            Collection<Plugin> plugins = getNutWebConfigure().getPluginManager().getAllPlugins();
            pluginInitializer.initialize(this, bindContext, plugins);

            // 注册默认的自动配置对象
            NutAutoConfigureProcessRegister autoConfigureProcessRegister = new NutAutoConfigureProcessRegister(applicationEventMulticaster,
                    (FactoryBeanRegister) applicationContext, getNutConfigure());
            autoConfigureProcessRegister.registerDefaultAutoConfigureBeanPostProcessor();

            // 处理注解信息
            doInitAnnotationMetadata(pluginInitializer, bindContext);

            autoConfigureProcessRegister.registerDefaultAutoConfigureBeanFactoryPostProcessor();

            // 执行BeanFactory后置方法
            doExecuteBeanFactoryPostProcess(true);

            boolean isWebApplicationType = ApplicationType.isWebApplicationType(applicationType);
            if (isWebApplicationType) {
                if (ApplicationType.isFullWebApplicationType(applicationType)) {
                    nutConfigureImpl.setSessionManager(BasicSessionManager.getInstance(threadPool));
                } else {
                    nutConfigureImpl.setSessionManager(new StateLessSessionManager());
                }
                nutConfigureImpl.setDispatcher(new NutDispatcher(getNutWebConfigure().getControllerManager(),
                        nutConfigureImpl.getPluginManager(), bindContext, applicationContext, postfixViewHandler));
                nutConfigureImpl.setServerContext(new BasicServerContext());
            }

            // 执行通过注解编程方式设置的插件的绑定方法
            Collection<Plugin> latestPlugins = getNutWebConfigure().getPluginManager().getAllPlugins();
            pluginInitializer.initialize(this, bindContext, latestPlugins);

            // 执行BeanFactory后置方法
            doExecuteBeanFactoryPostProcess(false);

            // 发布应用上下文启动完成事件
            applicationEventMulticaster.multicastEvent(new ApplicationContextStartedEvent(applicationContext));

            serverEventContext.setDispatcher(getNutWebConfigure().getDispatcher());
            serverEventContext.setControllerManager(getNutWebConfigure().getControllerManager());
            serverEventContext.setSessionManager(getNutWebConfigure().getSessionManager());
            serverEventContext.setPluginManager(getNutWebConfigure().getPluginManager());
            serverEventContext.setApplicationMetadata(applicationMetadata);
            Collection<ServerEventPlugin> serverEventPlugins = getNutWebConfigure().getPluginManager().getServerEventPlugins();

            // 服务启动前置方法
            for (ServerEventPlugin serverEventPlugin : serverEventPlugins) {
                try {
                    serverEventPlugin.beforeStart(serverEventContext);
                } catch (Exception e) {
                    String className = serverEventPlugin.getClass().getName();
                    logger.logp(Level.SEVERE, className, "beforeStart",
                            "InterceptorPlugin Plugin [" + className + "] Method Execute Failure.", e);
                }
            }

            if (isWebApplicationType) {
                // 处理脚本
                doInitScriptExpression(mergeNutConfigure);

                // 输出所有注册的请求路径
                printPaths();

                // 处理静态资源
                doInitStaticResource(mergeNutConfigure);
            }
            //默认优先从配置参数中获取是否安全启动，其次从调用run方法的参数中获取，最后不使用安全的套接字启动
            boolean secure = mergeNutConfigure.isServerSecurity() != null ? mergeNutConfigure.isServerSecurity() : false;
            applicationMetadata.setSecureServer(secure);
            //默认优先从配置参数中获取端口号，其次从调用run方法的参数中获取，最后使用默认的端口号启动
            int port = mergeNutConfigure.getServerPort() != null ? mergeNutConfigure.getServerPort() : secure ? HTTPS_PORT : HTTP_PORT;
            applicationMetadata.setServerPort(port);

            if (isWebApplicationType) {
                nutServer = buildNutServer(mergeNutConfigure);
                applicationMetadata.setServerType(nutServerFactory.getServerType(nutServer));
            }

            applicationMetadata.setProcessId(getProcessId());
            if (isWebApplicationType) {
                // 打印服务信息
                printWebServerInfo(applicationType, secure, port, startTime);

                // 启动服务
                nutServerRunThread = startNutServer(port);

                // 注册服务关闭钩子函数
                registerShutdownHook();
            } else {
                printBaseServerInfo(applicationType, startTime);
            }
            status = ServerStatus.STARTED.getStatus();

            // 发布服务启动完成事件
            applicationEventMulticaster.multicastEvent(new ApplicationStartedEvent(this));

            // 服务启动后置方法
            for (ServerEventPlugin serverEventPlugin : serverEventPlugins) {
                try {
                    serverEventPlugin.afterStart(serverEventContext);
                } catch (Exception e) {
                    String className = serverEventPlugin.getClass().getName();
                    logger.logp(Level.SEVERE, className, "afterStart",
                            "InterceptorPlugin Plugin [" + className + "] Method Execute Failure.", e);
                }
            }

            // 执行LazyInject注解的延迟注入操作
            ((BaseApplicationContext) applicationContext).afterApplicationInitialized();

            // 执行Nut Runner函数
            executeNutRunner(args);

            if (applicationType == ApplicationType.STANDARD) {
                close();
            } else if (applicationType == ApplicationType.STANDARD_BLOCKED) {
                applicationBlocker.block();
                close();
            }
        } catch (NutException e) {
            logger.log(Level.SEVERE, e.getMessage(), e.getCause() == null ? e : e.getCause());
            if (nutServerRunThread != null) {
                nutServerRunThread.interrupt();
            }
            close();
        } catch (Throwable e) {
            logger.log(Level.SEVERE, "Nut Server Runtime Failures.", e);
            if (nutServerRunThread != null) {
                nutServerRunThread.interrupt();
            }
            close();
        }

        return applicationContext;
    }

    /**
     * Nut 启动的主方法
     * @param serverType 服务启动类型
     * @param mainClass 启动主类
     * @param port 本地监听的端口号
     * @param secure 是否已安全套接字方式启动项目
     * @param args 启动参数
     * @return 应用上下文
     */
    public ApplicationContext run(ServerType serverType, Class<?> mainClass, Integer port, Boolean secure, String[] args) {
        NutConfiguration nutConfiguration = NutConfigurationBuilder.newInstance()
                .setServerType(serverType)
                .setApplicationType(ApplicationType.WEB)
                .setMainClass(mainClass)
                .setPort(port)
                .setSecure(secure)
                .build();
        return run(nutConfiguration, args);
    }

    /**
     * 关闭 Nut Server 的方法
     * @param force 是否强制关闭，如果强制关闭将会调用 {@link System#exit(int)} 方法
     */
    public void close(boolean force) {
        if (status == ServerStatus.CLOSING.getStatus() || status == ServerStatus.CLOSED.getStatus()) {
            throw new NutException("Nut Server Closing Or Closed.");
        }
        status = ServerStatus.CLOSING.getStatus();
        logger.info("Nut Server Closing.");

        // 发布服务关闭时事件
        applicationEventMulticaster.multicastEvent(new ApplicationClosingEvent(this));

        // 关闭应用上下文
        if (applicationContext != null) {
            try {
                applicationContext.close();
            } catch (Exception e) {
                logger.log(Level.SEVERE, "ApplicationContext Close Failure.", e);
            }
        }

        // 服务关闭前置方法
        for (ServerEventPlugin serverEventPlugin : getNutWebConfigure().getPluginManager().getServerEventPlugins()) {
            try {
                serverEventPlugin.beforeClose(serverEventContext);
            } catch (Exception e) {
                String className = serverEventPlugin.getClass().getName();
                logger.logp(Level.SEVERE, className, "beforeClose",
                        "InterceptorPlugin Plugin [" + className + "] Method Execute Failure.", e);
            }
        }

        if (force) {
            System.exit(-1);
        } else {
            if (nutServer != null) {
                try {
                    nutServer.close();
                } catch (IOException e) {
                    logger.logp(Level.SEVERE, NutServer.class.getName(), "close", "NutServer Close Fail.", e);
                }
            }
            if (threadPool != null) {
                threadPool.close();
            }
            try {
                if (watchService != null) {
                    watchService.close();
                }
            } catch (IOException e) {
                logger.logp(Level.SEVERE, WatchService.class.getName(), "close", "WatchService Close Fail.", e);
            }
        }

        // 服务关闭后置方法
        for (ServerEventPlugin serverEventPlugin : getNutWebConfigure().getPluginManager().getServerEventPlugins()) {
            try {
                serverEventPlugin.afterClose(serverEventContext);
            } catch (Exception e) {
                String className = serverEventPlugin.getClass().getName();
                logger.logp(Level.SEVERE, className, "afterClose",
                        "InterceptorPlugin Plugin [" + className + "] Method Execute Failure.", e);
            }
        }

        logger.info("Nut Server Closed.");
        status = ServerStatus.CLOSED.getStatus();
    }

    /**
     * 关闭 Nut Server 的方法
     *
     * @see #close(boolean)
     */
    public void close() {
        close(false);
    }

    /**
     * 获取Nut Banner对象
     * @return Nut Banner对象
     */
    public NutBanner getBanner() {
        return nutBanner;
    }

    /**
     * 获取程序运行类型
     * @return 程序运行类型
     */
    public ApplicationType getApplicationType() {
        return applicationType;
    }

    /**
     * 获取Nut基础配置对象
     * @return Nut基础配置对象
     */
    public BasicNutConfigure getBasicConfigure() {
        return basicNutConfigure;
    }

    /**
     * 获取自动探测注册器
     * @return 自动探测注册器
     */
    public AutoDetectorRegister getAutoDetectorRegister() {
        return ((DefaultAutoDetectorHandler) autoDetectorHandler).getAutoDetectorRegister();
    }

    /**
     * 获取Nut Web配置对象
     * @return Nut Web配置对象
     */
    public NutWebConfigure getNutWebConfigure() {
        return nutConfigureImpl;
    }

    /**
     * 获取Nut 配置对象
     * @return Nut 配置对象
     */
    public NutConfigure getNutConfigure() {
        return nutConfigureImpl;
    }

    /**
     * 获取Nut应用上下文对象
     * @return Nut应用上下文对象
     */
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 获取Nut Web应用上下文对象
     * @return Web应用上下文对象
     */
    public ApplicationContext getWebApplicationContext() {
        return webApplicationContext;
    }

    /**
     * 获取应用元数据信息
     * @return 应用元数据信息
     */
    public ApplicationMetadata getApplicationMetadata() {
        return applicationMetadata;
    }

    /**
     * 获取Nut服务执行状态
     * @return Nut服务执行状态
     */
    public int getNutStatus() {
        return status;
    }

    /**
     * 获取应用事件广播器
     * @return 应用事件广播器
     */
    public ApplicationEventMulticaster getApplicationEventMulticaster() {
        return applicationEventMulticaster;
    }

    /**
     * 设置 Nut 的 Controller 管理器
     * @param controllerManager Controller 管理器
     */
    public void setControllerManager(ControllerManager controllerManager) {
        nutConfigureImpl.setControllerManager(controllerManager);
    }

    /**
     * 设置 Nut 的 {@link SessionManager}
     * @param sessionManager {@link SessionManager}
     */
    public void setSessionManager(SessionManager sessionManager) {
        nutConfigureImpl.setSessionManager(sessionManager);
    }

    /**
     * 设置 Nut 的 {@link PluginManager}
     * @param pluginManager {@link PluginManager}
     */
    public void setPluginManager(PluginManager pluginManager) {
        nutConfigureImpl.setPluginManager(pluginManager);
    }

    /**
     * 获取 Nut 的 {@link ThreadPool}
     * @return Nut 的 {@link ThreadPool}
     */
    public ThreadPool getDefaultThreadPool() {
        return threadPool;
    }

    /**
     * 构建Nut服务对象
     * @param basicNutConfigure 配置信息
     * @return Nut服务对象
     */
    private NutServer buildNutServer(BasicNutConfigure basicNutConfigure) {
        return nutServerFactory.buildServer(this, basicNutConfigure);
    }

    /**
     * 启动Nut服务
     * @param port 端口号
     * @return Nut服务线程对象
     */
    private Thread startNutServer(int port) {
        Thread nutServerRunThreader = new Thread(new ThreadGroup("nutWebGroup"), () -> {
            try {
                WebSocketRegisterFactory webSocketRegisterFactory = applicationContext.getBean(WebSocketRegisterFactory.class);
                if (webSocketRegisterFactory != null) {
                    Collection<WebSocketConfiguration> webSocketConfigurations = webSocketRegisterFactory.getWebSocketConfigurations();
                    if (webSocketConfigurations != null && !webSocketConfigurations.isEmpty()) {
                        if (nutServer instanceof WebSocketServer) {
                            WebSocketServer webSocketServer = (WebSocketServer) nutServer;
                            webSocketServer.checkDependExist();
                            webSocketServer.registerEndpoints(webSocketConfigurations);
                        } else {
                            throw new NutException("Application Used WebSocket, But Current Server[" + nutServer.getClass().getName() + "] Not Support.");
                        }
                    }
                }
                nutServer.startServer(buildNutServerConfigure(port));
            } catch (Exception e) {
                logger.log(Level.SEVERE, "Nut Server Runtime Failures.", e);
                close();
            }
        }, "nutWebMain");
        nutServerRunThreader.start();
        return nutServerRunThreader;
    }

    /**
     * 构建Nut Server配置接口对象
     * @param port 服务启动端口
     * @return Nut Server配置接口对象
     */
    private NutServerConfigure buildNutServerConfigure(int port) {
        DefaultNutServerConfigure nutServerConfigure = new DefaultNutServerConfigure();
        nutServerConfigure.setNutApplication(this);
        nutServerConfigure.setPort(port);
        NutWebConfigure webConfigure = getNutWebConfigure();
        nutServerConfigure.setServerContext(webConfigure.getServerContext());
        nutServerConfigure.setDispatcher(webConfigure.getDispatcher());
        nutServerConfigure.setControllerManager(webConfigure.getControllerManager());
        nutServerConfigure.setSessionManager(webConfigure.getSessionManager());
        nutServerConfigure.setPluginManager(webConfigure.getPluginManager());
        nutServerConfigure.setServerRequestConfiguration(buildServerRequestConfiguration());
        return nutServerConfigure;
    }

    /**
     * 构建请求配置接口对象
     * @return 请求配置接口对象
     */
    private ServerRequestConfiguration buildServerRequestConfiguration() {
        DefaultServerRequestConfiguration serverRequestConfiguration = new DefaultServerRequestConfiguration();
        serverRequestConfiguration.setMaxRequestSize(basicNutConfigure.getMaxRequestSize());
        return serverRequestConfiguration;
    }

    /**
     * 执行Nut Runner函数
     * @param args 启动参数
     */
    private void executeNutRunner(String[] args) {
        for (CommandLineRunner commandLineRunner : nutConfigureImpl.getCommandLineRunners()) {
            try {
                commandLineRunner.run(args);
            } catch (Exception e) {
                logger.logp(Level.SEVERE, Nut.class.getName(), "executeNutRunner",
                        "CommandLineRunner class [" + commandLineRunner.getClass().getName() + "] Execute Fail", e);
            }
        }

        for (ApplicationRunner applicationRunner : nutConfigureImpl.getApplicationRunners()) {
            try {
                applicationRunner.run(applicationMetadata);
            } catch (Exception e) {
                logger.logp(Level.SEVERE, Nut.class.getName(), "executeNutRunner",
                        "ApplicationRunner class [" + applicationRunner.getClass().getName() + "] Execute Fail", e);
            }
        }
    }

    /**
     * 打印当前已经注册到 {@link ControllerManager} 的 Controller
     */
    private void printPaths() {
        for (Map.Entry<ControllerMetadata, Controller> entry : getNutWebConfigure().getControllerManager().getAllController().entrySet()) {
            ControllerMetadata metadata = entry.getKey();
            Controller controller = entry.getValue();
            String pathMsg = "Path[" + metadata.getPath() + "], Alias["
                    + String.join(",", metadata.getAlias())
                    + "], Source[" + metadata.getControllerSource()
                    + "] Registered";
            if (metadata.getControllerSource() == ControllerSource.DEFAULT || metadata.getControllerSource() == ControllerSource.STATIC) {
                pathMsg += " To Controller Class[" + controller.getClass().getName() + "]";
            } else {
                pathMsg += ".";
            }
            logger.info(pathMsg);
        }
    }

    /**
     * 打印Web服务信息
     * @param applicationType 应用类型
     * @param secure 是否以安全的套接字启动
     * @param port 端口号
     * @param startTime 服务开始启动时间
     */
    private void printWebServerInfo(ApplicationType applicationType, boolean secure, int port, long startTime) {
        String ipInfo = IPUtils.getAllLocalIp().values()
                .stream()
                .flatMap(Collection::stream)
                .map(s -> "\t" + (secure ? "https" : "http") + "://" + s + ":" + port)
                .collect(Collectors.joining("\n"));
        logger.info("Nut Server Run At: \n" + ipInfo);

        printBaseServerInfo(applicationType, startTime);
    }

    /**
     * 打印基础服务信息
     * @param applicationType 应用类型
     * @param startTime 服务开始启动时间
     */
    private void printBaseServerInfo(ApplicationType applicationType, long startTime) {
        logger.info("Nut Server Run Application Type: [" + applicationType + "]");
        logger.info("Nut Run Host [" + getHostname() + "] With PID [" + applicationMetadata.getProcessId() + "]");
        logger.info("Nut Server Load [" + (System.currentTimeMillis() - startTime) + "] ms");
    }

    /**
     * 获取主机名
     * @return 主机名
     */
    private String getHostname() {
        String hostname = "";
        try {
            InetAddress address = InetAddress.getLocalHost();
            hostname = address.getHostName();
        } catch (UnknownHostException e) {
            logger.warning("Not Obtain Host Information");
        }
        return hostname;
    }

    /**
     * 获取进程号
     * @return 进程号
     */
    private String getProcessId() {
        RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean();
        String jvmName = bean.getName();
        return jvmName.split("@")[0];
    }

    /**
     * 注册服务关闭钩子函数
     */
    private void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            if (status == ServerStatus.STARTING.getStatus() || status == ServerStatus.STARTED.getStatus()) {
                close(false);
            }
        }));
    }

    /**
     * 执行BeanFactory后置方法
     * @param priority 是否执行优先级后置处理器
     */
    private void doExecuteBeanFactoryPostProcess(boolean priority) {
        List<BeanFactoryPostProcessor> beans;
        if (priority) {
            Collection<BeanFactoryPriorityPostProcessor> priorityBeans = applicationContext.getBeans(BeanFactoryPriorityPostProcessor.class);
            beans = priorityBeans
                    .stream()
                    .map(p -> (BeanFactoryPostProcessor) p)
                    .collect(Collectors.toList());
        } else {
            beans = applicationContext.getBeans(BeanFactoryPostProcessor.class)
                    .stream()
                    .filter(p -> !BeanFactoryPriorityPostProcessor.class.isAssignableFrom(p.getClass()))
                    .collect(Collectors.toList());
        }
        if (!beans.isEmpty()) {
            beans.sort(Comparator.comparing(Order::getOrder));
            for (BeanFactoryPostProcessor beanFactoryPostProcessor : beans) {
                try {
                    beanFactoryPostProcessor.process(applicationContext);
                } catch (Exception e) {
                    if (e instanceof SuspendException) {
                        throw (SuspendException) e;
                    }
                    logger.logp(Level.SEVERE, beanFactoryPostProcessor.getClass().getName(), "process",
                            "BeanFactoryPostProcessor class [" + beanFactoryPostProcessor.getClass().getName() + "] Execute Fail", e);
                }
            }
        }
    }

    /**
     * 初始化启动主类
     * @param nutConfiguration nut配置对象
     * @param mainClass 启动主类
     */
    private void doInitMainClassSource(Class<?> mainClass, NutConfiguration nutConfiguration) {
        getNutConfigure().addBasePackage(mainClass);
        if (nutConfiguration.getApplicationType() == ApplicationType.TEST) {
            NutBootTest nutBootTest = mainClass.getAnnotation(NutBootTest.class);
            if (nutBootTest != null) {
                doInitWebConfigure(nutConfiguration, nutBootTest.baseScanPackage(), nutBootTest.baseScanClass(),
                        null, null, nutBootTest.enablePlugins(), nutBootTest.ignoreAutoDetectors());
            }
        } else {
            NutBootApplication nutApplication = mainClass.getAnnotation(NutBootApplication.class);
            if (nutApplication != null) {
                doInitWebConfigure(nutConfiguration, nutApplication.baseScanPackage(), nutApplication.baseScanClass(),
                        nutApplication.serverType(), nutApplication.applicationType(), nutApplication.enablePlugins(),
                        nutApplication.ignoreAutoDetectors());
            }
        }
    }

    /**
     * 执行Web配置对象初始化
     * @param nutConfiguration Nut 配置对象
     * @param baseScanPackages 扫描的基础包路径
     * @param baseScanClasses 扫描的记录class对象
     * @param serverType 服务启动类型
     * @param applicationType 应用类型
     * @param enablerPlugins 启用的插件类数组
     * @param ignoreAutoDetectorClasses 要忽略的自动探测类数组
     */
    private void doInitWebConfigure(NutConfiguration nutConfiguration, String[] baseScanPackages, Class<?>[] baseScanClasses,
                                    ServerType serverType, ApplicationType applicationType, Class<? extends Plugin>[] enablerPlugins,
                                    Class<? extends AutoDetector>[] ignoreAutoDetectorClasses) {
        if (baseScanPackages != null) {
            for (String baseScanPackage : baseScanPackages) {
                getNutConfigure().addBasePackage(baseScanPackage);
            }
        }

        if (baseScanClasses != null) {
            for (Class<?> baseScanClass : baseScanClasses) {
                getNutConfigure().addBasePackage(baseScanClass);
            }
        }

        if (serverType != null) {
            nutConfiguration.setServerType(serverType);
        }

        if (applicationType != null) {
            nutConfiguration.setApplicationType(applicationType);
        }

        if (enablerPlugins != null) {
            for (Class<? extends Plugin> enablerPluginClass : enablerPlugins) {
                try {
                    getNutWebConfigure().getPluginManager().registerPlugin(enablerPluginClass);
                } catch (Exception e) {
                    logger.logp(Level.SEVERE, PluginManager.class.getName(), "registerPlugin",
                            "MainClass Plugin Class [ " + enablerPluginClass.getName() + "] Register Fail.", e);
                }
            }
        }

        if (ignoreAutoDetectorClasses != null) {
            for (Class<? extends AutoDetector> autoDetectorClass : ignoreAutoDetectorClasses) {
                getNutConfigure().addIgnoreAutoDetectClass(autoDetectorClass);
            }
        }
    }

    /**
     * 设置系统环境变量
     * @param env 系统环境变量
     * @param args 启动参数
     */
    private void doInitEnvironment(String env, String[] args) {
        if (env != null) {
            getNutConfigure().setEnvironment(env);
        }
        Environment environment = getNutConfigure().getEnvironment();
        Properties properties = environment.getEnvProperties();
        // 将系统环境变量设置进environment对象中
        System.getenv().forEach(properties::setProperty);
        // 将JVM参数设置进environment对象中
        properties.putAll(System.getProperties());
        // 将程序参数设置进environment对象中
        Arrays.stream(args)
                .filter(arg -> arg.contains("="))
                .map(arg -> arg.split("="))
                .filter(s -> s.length == 2)
                .forEach(s -> properties.setProperty(s[0].trim(), s[1].trim()));
        logger.info("Nut Active Environment Profile [" + environment.getEnvName() + "]");
    }

    /**
     * 通过SPI加载预置事件监听器
     */
    private void doLoadSpiApplicationEventListener() {
        ServiceLoader<ApplicationListener> serviceLoader = ServiceLoader.load(ApplicationListener.class, ClassLoaderUtils.getClassLoader());
        for (ApplicationListener applicationListener : serviceLoader) {
            applicationEventMulticaster.addApplicationListener(applicationListener);
        }
    }

    /**
     * 注册默认应用上下文组件
     */
    private void registerDefaultApplicationComponent() {
        FactoryBeanRegister factoryBeanRegister = ((FactoryBeanRegister) applicationContext);
        //将应用阻塞器注入到容器中
        if (applicationType == ApplicationType.STANDARD_BLOCKED) {
            factoryBeanRegister.registerBean("applicationBlocker", applicationBlocker, ApplicationBlocker.class);
        }
        // 将Nut应用对象注入到容器中
        factoryBeanRegister.registerBean("nutApplication", this, NutApplication.class);
        // 将环境对象注入到到容器中
        factoryBeanRegister.registerBean("environment", getNutConfigure().getEnvironment(), Environment.class,
                DefaultEnvironment.class);
        // 将线程池对象注入到容器中
        factoryBeanRegister.registerBean("threadPool", threadPool, ThreadPool.class, DefaultThreadPool.class);
        // 将事务注册器注入到容器中
        factoryBeanRegister.registerBean("transactionRegistry", new TransactionRegistry(applicationContext));
        // 将事件广播器注入到容器中
        factoryBeanRegister.registerBean("applicationEventMulticaster", applicationEventMulticaster,
                ApplicationEventMulticaster.class, DefaultApplicationEventMulticaster.class);
        // 将事件发布器注入到容器中
        factoryBeanRegister.registerBean("applicationEventPublisher", new DefaultApplicationEventPublisher(applicationEventMulticaster),
                ApplicationEventPublisher.class, DefaultApplicationEventPublisher.class);
        // 将定时调度执行器注入到容器中
        factoryBeanRegister.registerBean("scheduledExecutor", new ScheduledExecutor(applicationContext), ScheduledExecutor.class);
    }

    /**
     * 初始化自动探测器
     */
    private void doInitAutoDetect() {
        AutoDetectorRegister autoDetectorRegister = getAutoDetectorRegister();
        nutConfigureImpl.getAutoDetectors().forEach(autoDetectorRegister::registerAutoDetector);
        autoDetectorHandler.handle();
    }

    /**
     * 初始化注解信息
     * @param pluginInitializer 插件初始化器
     * @param bindContext  插件的绑定上下文对象
     */
    private void doInitAnnotationMetadata(BasePluginInitializer pluginInitializer, BindContext bindContext) {
        if (!nutConfigureImpl.getBasePackages().isEmpty()) {
            AnnotationScanHandler annotationScanHandler = new AnnotationScanHandler(this,
                    nutConfigureImpl.getBasePackages(), pluginInitializer, bindContext);
            annotationScanHandler.scan();
        }
    }

    /**
     * 初始化脚本资源
     * @param basicNutConfigure 配置对象
     */
    private void doInitScriptExpression(BasicNutConfigure basicNutConfigure) {
        boolean enableScript = basicNutConfigure.isEnableScript();
        if (enableScript) {
            String[] scriptPath = basicNutConfigure.getScriptPath();
            if (scriptPath.length > 0) {
                ExpressionScriptMetadataParser scriptMetadataParser = new ExpressionScriptMetadataParser(nutConfigureImpl.getCustomNutExpressions());
                FileScriptContext scriptContext = new FileScriptContext(scriptMetadataParser, basicNutConfigure.getScriptEncoding(), scriptPath);
                nutConfigureImpl.setFunctionContext(scriptContext);
                // 注册内置有效函数
                InternalFunctionRegister.getInstance().registerInternalFunction(scriptContext);
                // 注册自定义函数
                for (Function customFunction : nutConfigureImpl.getCustomScriptFunctions()) {
                    scriptContext.registerFunction(customFunction);
                }
                for (ControllerScript controllerScript : scriptContext.getControllerScripts()) {
                    ControllerPath controllerPath = controllerScript.toController();
                    registerScriptController(controllerPath);
                }

                // 开启脚本文件监控
                if (basicNutConfigure.isEnableScriptWatch()) {
                    startWatchScriptFile(basicNutConfigure, scriptPath);
                }
            }
        }
    }

    /**
     * 注册脚本Controller
     * @param controllerPath ControllerPath 对象
     */
    private void registerScriptController(ControllerPath controllerPath) {
        String[] paths = controllerPath.getPaths().stream().map(Path::getPath).toArray(String[]::new);
        if (paths.length == 0) {
            return;
        }
        String[] alias;
        if (paths.length > 1) {
            alias = new String[paths.length - 1];
            System.arraycopy(paths, 1, alias, 0, paths.length - 1);
        } else {
            alias = new String[0];
        }
        getNutWebConfigure().getControllerManager().registerController(controllerPath.getController(),
                ControllerSource.SCRIPT, paths[0], alias);
    }

    /**
     * 开启脚本文件监控
     * @param basicNutConfigure 配置对象
     * @param scriptPath 脚本文件路径
     */
    private void startWatchScriptFile(BasicNutConfigure basicNutConfigure, String[] scriptPath) {
        try {
            Set<URI> directories = new HashSet<>();
            for (String path : scriptPath) {
                directories.add(new File(path).getParentFile().toURI());
            }
            Set<java.nio.file.Path> watchPaths = new HashSet<>(directories.size());
            watchService = FileSystems.getDefault().newWatchService();
            for (URI uri : directories) {
                java.nio.file.Path path = Paths.get(uri);
                path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
                watchPaths.add(path);
            }

            threadPool.getScheduledThreadPool().scheduleAtFixedRate(
                    () -> {
                        //获取监听结果，没有返回null
                        WatchKey key = watchService.poll();

                        if (null == key) {
                            return;
                        }
                        for (WatchEvent<?> event : key.pollEvents()) {
                            WatchEvent.Kind<?> kind = event.kind();
                            if (kind.name().equals(StandardWatchEventKinds.ENTRY_MODIFY.name())) {
                                java.nio.file.Path path = (java.nio.file.Path) event.context();
                                for (java.nio.file.Path watchPath : watchPaths) {
                                    File scriptFile = watchPath.resolve(path).toFile();
                                    if (scriptFile.exists()) {
                                        refreshScriptContext(basicNutConfigure, scriptFile);
                                    }
                                }
                            }

                            key.reset();
                        }
                    }, 1, 10, TimeUnit.SECONDS);
        } catch (IOException e) {
            logger.logp(Level.SEVERE, Nut.class.getName(), "startWatchScriptFile",
                    "Start Script Watcher Fail.", e);
        }
    }

    /**
     * 刷新脚本上下文
     * @param basicNutConfigure 配置对象
     * @param scriptFile 脚本文件
     */
    private void refreshScriptContext(BasicNutConfigure basicNutConfigure, File scriptFile) {
        logger.info("Script Context Ready To Refresh...");
        ExpressionScriptMetadataParser scriptMetadataParser = new ExpressionScriptMetadataParser(nutConfigureImpl.getCustomNutExpressions());
        FileScriptContext scriptContext = new FileScriptContext(scriptMetadataParser, basicNutConfigure.getScriptEncoding(),
                scriptFile.getAbsolutePath());
        List<ControllerScript> controllerScripts = scriptContext.getControllerScripts((
                (AbstractScriptContext) getNutConfigure().getFunctionContext()).getFunctionExecutor());
        for (ControllerScript controllerScript : controllerScripts) {
            ControllerPath controllerPath = controllerScript.toController();
            controllerPath.getPaths().forEach(p -> logger.info("Path[" + p + "] Refresh Registered To Controller["
                    + controllerPath.getController() + "]"));

            registerScriptController(controllerPath);
        }
        logger.info("Script Context Refresh Done, Total " + controllerScripts.size() + " Script Update.");
    }

    /**
     * 初始化静态资源
     * @param basicNutConfigure 配置对象
     */
    private void doInitStaticResource(BasicNutConfigure basicNutConfigure) {
        getNutWebConfigure().getControllerManager().setStaticDirectoryPreview(basicNutConfigure.isEnableStaticDirectoryPreview());
        String[] staticResourceDirectory = basicNutConfigure.getStaticResourceDirectory();
        if (staticResourceDirectory.length > 0) {
            getNutWebConfigure().getControllerManager().addStaticResourceDirs(staticResourceDirectory);
            String[] staticResourcePaths = basicNutConfigure.getStaticResourcePaths();
            if (staticResourcePaths.length == 0) {
                getNutWebConfigure().getControllerManager().addStaticResourcePaths("/static");
                logger.info("Resource [" + String.join(",", staticResourceDirectory)
                        + "] Registered To Path [/static]");
            } else {
                getNutWebConfigure().getControllerManager().addStaticResourcePaths(staticResourcePaths);
                logger.info("Resource [" + String.join(",", staticResourceDirectory)
                        + "] Registered To Path [" + String.join(",", staticResourcePaths) + "]");
            }
        }
    }
}
